package buffer;

import file.BlockId;
import file.FileMgr;
import file.Page;
import log.LogMgr;
import lombok.extern.slf4j.Slf4j;

/**
 * An individual buffer. A databuffer wraps a page
 * and stores information about its status,
 * such as the associated disk block,
 * the number of times the buffer has been pinned,
 * whether its contents have been modified,
 * and if so, the id and lsn of the modifying transaction.
 * @author Edward Sciore
 */
@Slf4j
public class Buffer {

    private FileMgr fm;

    private LogMgr lm;

    private Page contents;

    private BlockId blk = null;

    private int pins = 0;

    private int txnum = -1;

    private int lsn = -1;

    public Buffer(FileMgr fm, LogMgr lm) {
        this.fm = fm;
        this.lm = lm;
        contents = new Page(fm.blockSize());
    }

    public Page contents() {
        return contents;
    }

    /**
     * Returns a reference to the disk block
     * allocated to the buffer.
     * @return a reference to a disk block
     */
    public BlockId block() {
        return blk;
    }

    public void setModified(int txnum, int lsn) {
        this.txnum = txnum;
        if (lsn >= 0)
            this.lsn = lsn;
    }

    /**
     * Return true if the buffer is currently pinned
     * (that is, if it has a nonzero pin count).
     * @return true if the buffer is pinned
     */
    public boolean isPinned() {
        return pins > 0;
    }

    public int modifyingTx() {
        return txnum;
    }

    void assignToBlock(BlockId b) {
        flush();
        blk = b;
        fm.read(blk, contents);
        pins = 0;
    }

    /**
     * Write the buffer to its disk block if it is dirty.
     */
    void flush() {
        if (txnum >= 0) {
            log.info("Flushing to the disk: block file {}, block number {}", blk.fileName(), blk.number());
            lm.flush(lsn);
            fm.write(blk, contents);
            txnum = -1;
        }
    }

    /**
     * Increase the buffer's pin count.
     */
    void pin() {
        pins++;
    }

    /**
     * Decrease the buffer's pin count.
     */
    void unpin() {
        pins--;
    }
}
